package com.test.shiro.realm;

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import java.util.HashSet;
import java.util.Set;

/**
 * @author lzy
 * @version v1.0
 * Create DateTime: 2019/9/8 15:10
 */
//public class ShiroRealm extends AuthenticatingRealm {
public class ShiroRealm extends AuthorizingRealm {

    public static void main(String[] args) {
        String hashAlgorithmName = "MD5";
        Object credentials = "123456";
        ByteSource credentialsSalt = ByteSource.Util.bytes("user");
        Object salt = credentialsSalt;
        int hashIterations = 1024;
        final SimpleHash simpleHash = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);

        System.out.println(simpleHash);
    }

    /**
     * 实现认证
     *
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("First AuthenticationInfo " + token);
        // 1. 把AuthenticationToken转换为UsernamePasswordToken
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        // 2.从UsernamePasswordToken中获取username
        final String username = upToken.getUsername();
        // 3.调用数据库方法，从数据库中获取username对应的用户记录
        System.out.println("从数据库中获取username" + username + "对应的用户信息");

        // 4.若用户不存在，则可以抛出认证异常
        if ("unknown".equals(username)) {
            throw new UnknownAccountException();
        }
        // 5.根据用户信息的情况，决定是否要抛出其他的异常
        if ("monster".equals(username)) {
            throw new LockedAccountException();
        }
        // 6.根据用户的情况，来构建AuthenticationInfo对象并返回, 通常使用的实现类为SimpleAuthenticationInfo
        // 以下信息是从数据库中获取的
        //1.principal: 认证的信息，可以是username，也可以是数据表对应的实体类对象
        Object principal = username;
        //2.credentials: 密码
        Object credentials = "fc1709d0a95a6be30bc5926fdb7f22f4";
        //3. realname: 当前realm对象的name，调用父类的getName()方法即可
        String realmName = getName();
        //4. 盐值
        ByteSource credentialsSalt = ByteSource.Util.bytes(username);
        if ("admin".equals(username)) {
            credentials = "038bdaf98f2037b31f1e75b5b4c9b26e";
        }
        if ("user".equals(username)) {
            credentials = "098d2c478e9c11555ce2823231e02ec1";

        }

//        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal,credentials,realmName);
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
        return info;
    }

    /**
     * 实现授权，授权会被shiro回调的方法
     *
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("doGetAuthorizationInfo");
        //1.从PrincipalCollection中获取登陆用户的信息
        Object principal = principals.getPrimaryPrincipal();
        //2.利用登陆用户的信息来获取当前用户的角色或者权限（可能需要查询数据库）
        Set<String> roles = new HashSet<>(16);
        roles.add("user");
        if ("admin".equals(principal)) {
            roles.add("admin");
        }
        //3.创建SimpleAuthorizationInfo，并设置其roles属性
        SimpleAuthorizationInfo infos = new SimpleAuthorizationInfo(roles);
        // 4. 返回SimpleAuthorizationInfo对象
        return infos;
    }
}
